package web_http

import(
	"log"
	"time"
	"io/ioutil"
	"fmt"
	"net/http"
	"client2/config"
	"client2/zkp"
	"encoding/json"
	"bytes"
)


// 获取挑战（异步安全版本）
func GetChallenge(deviceID string, BASE_URL string) (*ChallengeResponse, error) {
	log.Println("获取挑战...")
	log.Printf("设备ID: %s", deviceID)
	
	url := BASE_URL + "/api/v1/auth/challenge"
	log.Printf("请求URL: %s", url)
	
	reqBody, err := json.Marshal(map[string]string{
		"device_id": deviceID,
	})
	if err != nil {
		return nil, err
	}
	
	client := &http.Client{Timeout: 5 * time.Second}
	resp, err := client.Post(url, "application/json", bytes.NewBuffer(reqBody))
	if err != nil {
		return nil, fmt.Errorf("网络请求失败: %v", err)
	}
	defer resp.Body.Close()
	
	log.Printf("响应状态码: %d", resp.StatusCode)
	
	body, _ := ioutil.ReadAll(resp.Body)
	
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("服务器返回错误: %s, 响应: %s", resp.Status, string(body))
	}
	
	var challenge ChallengeResponse
	if err := json.Unmarshal(body, &challenge); err != nil {
		return nil, err
	}
	
	return &challenge, nil
}

// 启动认证流程（完全异步，不阻塞传感器） - 支持 SensorDeviceConfig
// saveConfigFunc: 认证成功后调用此函数保存配置
func StartAuthentication(sensorConfig *config.SensorDeviceConfig, state *DeviceState, BASE_URL string, prover *zkp.Prover, saveConfigFunc func()) {
	// 添加 panic 恢复机制，防止认证流程错误导致 goroutine 崩溃
	defer func() {
		if r := recover(); r != nil {
			log.Printf("[%s] ❌ 认证流程发生 panic: %v，将在10秒后重试", sensorConfig.DeviceID, r)
			// 等待后重新启动认证流程
			time.Sleep(10 * time.Second)
			go StartAuthentication(sensorConfig, state, BASE_URL, prover, saveConfigFunc)
		}
	}()

	log.Printf("启动设备 %s 的认证流程...", sensorConfig.DeviceID)

	// 认证循环
	for {
		log.Printf("=== [%s] 开始新认证周期 ===", sensorConfig.DeviceID)

		// 异步获取挑战
		challenge, err := GetChallenge(sensorConfig.DeviceID, BASE_URL)
		if err != nil {
			log.Printf("[%s] 获取挑战失败: %v", sensorConfig.DeviceID, err)
			time.Sleep(10 * time.Second) // 失败后等待更长时间
			continue
		}

		log.Printf("[%s] 挑战响应: ChallengeID=%s", sensorConfig.DeviceID, challenge.ChallengeID)

		state.ChallengeID = challenge.ChallengeID
		state.Nonce = challenge.Nonce

		// 生成零知识证明（本地计算，不涉及网络）
		log.Printf("[%s] 生成零知识证明...", sensorConfig.DeviceID)
		proofBase64, deviceIDHex, response, err := prover.GenerateProof(
			sensorConfig.Secret,
			sensorConfig.DeviceID,
			state.Nonce,
			sensorConfig.Commitment,
		)
		if err != nil {
			log.Printf("[%s] 生成证明失败: %v", sensorConfig.DeviceID, err)
			time.Sleep(10 * time.Second)
			continue
		}
		log.Printf("[%s] 证明生成成功 (长度: %d bytes)", sensorConfig.DeviceID, len(proofBase64))

		// 异步验证证明（使用 deviceIDHex 作为 public_witness 中的 device_id）
		verifyResp, err := VerifyProof(sensorConfig.DeviceID, state.ChallengeID, proofBase64, deviceIDHex, state.Nonce, sensorConfig.Commitment, response, BASE_URL)
		if err != nil {
			log.Printf("[%s] 验证证明失败: %v", sensorConfig.DeviceID, err)
			time.Sleep(10 * time.Second)
			continue
		}

		if verifyResp.Success {
			// 更新内存中的状态
			state.Token = verifyResp.Token
			expiry, _ := time.Parse(time.RFC3339, verifyResp.ExpiresAt)
			state.TokenExpiry = expiry

			// ✅ 更新配置文件中的令牌
			sensorConfig.Token = verifyResp.Token
			sensorConfig.TokenExpiry = expiry

			// 保存配置到文件
			if saveConfigFunc != nil {
				saveConfigFunc()
				log.Printf("[%s] 令牌已保存到配置文件", sensorConfig.DeviceID)
			}

			log.Printf("[%s] ✅ 认证成功! 有效期至: %s", sensorConfig.DeviceID, verifyResp.ExpiresAt)
		} else {
			log.Printf("[%s] ❌ 认证失败: %s", sensorConfig.DeviceID, verifyResp.Message)
			time.Sleep(10 * time.Second)
			continue
		}

		// 等待令牌接近过期时刷新令牌
		log.Printf("[%s] 等待令牌接近过期...(提前5分钟刷新)", sensorConfig.DeviceID)
		for time.Now().Before(state.TokenExpiry.Add(-5 * time.Minute)) {
			time.Sleep(30 * time.Second) // 检查间隔
		}

		// 尝试刷新令牌（无需ZKP，更高效）
		log.Printf("[%s] 令牌即将过期，尝试刷新令牌...", sensorConfig.DeviceID)
		refreshResp, err := RefreshToken(state.Token, BASE_URL)
		if err != nil {
			log.Printf("[%s] ⚠️  刷新令牌失败: %v，将进行完整ZKP认证", sensorConfig.DeviceID, err)
			// 刷新失败，继续循环进行完整ZKP认证
			continue
		}

		// 刷新成功，更新令牌
		state.Token = refreshResp.Token
		expiry, _ := time.Parse(time.RFC3339, refreshResp.ExpiresAt)
		state.TokenExpiry = expiry
		sensorConfig.Token = refreshResp.Token
		sensorConfig.TokenExpiry = expiry

		// 保存刷新后的令牌到配置文件
		if saveConfigFunc != nil {
			saveConfigFunc()
			log.Printf("[%s] 刷新后的令牌已保存到配置文件", sensorConfig.DeviceID)
		}

		log.Printf("[%s] ✅ 令牌刷新成功! 新有效期至: %s", sensorConfig.DeviceID, refreshResp.ExpiresAt)
	}
}

// RefreshToken 刷新JWT令牌（无需ZKP认证）
func RefreshToken(currentToken string, BASE_URL string) (*VerifyResponse, error) {
	log.Println("刷新JWT令牌...")

	url := BASE_URL + "/api/v1/auth/refresh"
	log.Printf("请求URL: %s", url)

	client := &http.Client{Timeout: 5 * time.Second}
	req, err := http.NewRequest("POST", url, nil)
	if err != nil {
		return nil, fmt.Errorf("创建请求失败: %v", err)
	}

	// 设置Authorization头
	req.Header.Set("Authorization", "Bearer "+currentToken)
	req.Header.Set("Content-Type", "application/json")

	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("网络请求失败: %v", err)
	}
	defer resp.Body.Close()

	log.Printf("RefreshToken 响应状态码: %d", resp.StatusCode)

	body, _ := ioutil.ReadAll(resp.Body)

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("刷新令牌失败: %s, 响应: %s", resp.Status, string(body))
	}

	var refreshResp VerifyResponse
	if err := json.Unmarshal(body, &refreshResp); err != nil {
		return nil, err
	}

	return &refreshResp, nil
}

// 验证证明（异步安全版本）
func VerifyProof(deviceID, challengeID, proof, publicDeviceID, publicChallenge, publicCommitment, publicResponse string, BASE_URL string) (*VerifyResponse, error) {
	log.Println("验证证明...")

	url := BASE_URL + "/api/v1/auth/verify"
	log.Printf("请求URL: %s", url)
	
	req := VerifyRequest{
		DeviceID:    deviceID,
		ChallengeID: challengeID,
		Proof: struct {
			Proof        string `json:"proof"`
			PublicWitness struct {
				DeviceID   string `json:"device_id"`
				Challenge  string `json:"challenge"`
				Commitment string `json:"commitment"`
				Response   string `json:"response"`
			} `json:"public_witness"`
		}{
			Proof: proof,
			PublicWitness: struct {
				DeviceID   string `json:"device_id"`
				Challenge  string `json:"challenge"`
				Commitment string `json:"commitment"`
				Response   string `json:"response"`
			}{
				DeviceID:   publicDeviceID,
				Challenge:  publicChallenge,
				Commitment: publicCommitment,
				Response:   publicResponse,
			},
		},
	}
	
	reqBody, err := json.Marshal(req)
	if err != nil {
		return nil, err
	}
	
	client := &http.Client{Timeout: 5 * time.Second}
	resp, err := client.Post(url, "application/json", bytes.NewBuffer(reqBody))
	if err != nil {
		return nil, fmt.Errorf("VerifyProof 网络请求失败: %v", err)
	}
	defer resp.Body.Close()
	
	log.Printf("VerifyProof 响应状态码: %d", resp.StatusCode)
	
	body, _ := ioutil.ReadAll(resp.Body)
	
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("VerifyProof 服务器返回错误: %s, 响应: %s", resp.Status, string(body))
	}
	
	var verifyResp VerifyResponse
	if err := json.Unmarshal(body, &verifyResp); err != nil {
		return nil, err
	}
	
	return &verifyResp, nil
}
